﻿using Microsoft.EntityFrameworkCore;
using WhutDoomCheck.Server.Entities;
using WhutDoomCheck.Shared.HttpModels;

namespace WhutDoomCheck.Server.Services
{
    public class RecordService
    {
        public RecordService(ApplicationDbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        private readonly ApplicationDbContext dbContext;

        public async Task AddAsync(string sno, int? oldDoomId, int? newDoomId, string? oldAdress, string? newAdress)
        {
            EnsureStudentValid(sno);

            // 有进行中或已完成的请求则不可以添加新请求
            var recordQuery = dbContext.Records.Where(x => x.Sno == sno)
                                               .Where(x => x.Status == Status.WorkInProgress || x.Status == Status.Finished);

            if (recordQuery.Any()) throw new InvalidOperationException("存在未处理或已完成的请求时不可提交新的请求");

            // 添加记录时默认状态为等待审核
            var record = new Record()
            {
                Sno = sno,
                OldDoomId = oldDoomId,
                NewDoomId = newDoomId,
                OldAddress = oldAdress,
                NewAddress = newAdress,
                Status = Status.WorkInProgress,
                Comment = "系统自动通过审核"
            };

            this.dbContext.Records.Add(record);
            await this.dbContext.SaveChangesAsync();
        }
        
        public async Task<IList<RecordReview>> GetPendingReviewRequestsAsync(string teacherNumber)
        {
            var teacher = EnsureTeacherValid(teacherNumber);
            var query = dbContext.Records.Where(record => record.Status == Status.WorkInProgress)
                                 .Include(record => record.Student)
                                 .ThenInclude(student => student.Counsellor)
                                 .Where(record => record.Student.CounsellorId == teacherNumber)
                                 .Select(x => new RecordReview
                                 {
                                     Id = x.Id,
                                     Name = x.Student.Name,
                                     Sno = x.Sno,
                                     OldDoom = x.OldDoom == null ? null : $"{x.OldDoom.Area}-{x.OldDoom.Building}-{x.OldDoom.RoomNumber}",
                                     NewDoom = x.NewDoom == null ? null : $"{x.NewDoom.Area}-{x.NewDoom.Building}-{x.NewDoom.RoomNumber}",
                                     OldAddress = x.OldAddress,
                                     NewAddress = x.NewAddress,
                                     Time = x.CreateTime
                                 });

            return await query.ToListAsync();
        }

        public async Task<IList<RecordReviewHistory>> GetReviewHistory(string teacherNumber)
        {
            var teacher = EnsureTeacherValid(teacherNumber);
            var query = dbContext.Records.Where(record => record.Status != Status.WorkInProgress)
                                         .Include(record => record.Student)
                                         .ThenInclude(student => student.Counsellor)
                                         .Where(record => record.Student.CounsellorId == teacherNumber)
                                         .Select(x => new RecordReviewHistory
                                         {
                                             Id = x.Id,
                                             Name = x.Student.Name,
                                             Sno = x.Sno,
                                             OldDoom = x.OldDoom == null ? null : $"{x.OldDoom.Area}-{x.OldDoom.Building}-{x.OldDoom.RoomNumber}",
                                             NewDoom = x.NewDoom == null ? null : $"{x.NewDoom.Area}-{x.NewDoom.Building}-{x.NewDoom.RoomNumber}",
                                             OldAddress = x.OldAddress,
                                             NewAddress = x.NewAddress,
                                             Time = x.CreateTime,
                                             Status = x.Status == Status.Finished ? "已通过" : "已驳回",
                                             Comment = x.Comment,
                                         });
            return await query.ToListAsync();
        }

        public async Task SetStateAsync(string sno, Status status)
        {
            EnsureStudentValid(sno);

            var record = GetLatestRecordAsync(sno);

            if (record is null) throw new InvalidOperationException("不存在可操作的请求");
            record.Status = status;

            await this.dbContext.SaveChangesAsync();
        }

        public Status GetState(string sno)
        {
            EnsureStudentValid(sno);
            var record = GetLatestRecordAsync(sno);

            return record?.Status ?? Status.NotCommited;
        }

        private Record? GetLatestRecordAsync(string sno) =>
            dbContext.Records.Where(x => x.Sno == sno)
                             .OrderByDescending(x => x.CreateTime)
                             .FirstOrDefault();

        private void EnsureStudentValid(string sno)
        {
            var query = dbContext.Students.AsNoTracking().Where(x => x.Sno == sno);
            if (!query.Any()) throw new ArgumentException("学号不存在");
        }

        private Counsellor EnsureTeacherValid(string teacherNo)
        {
            var query = dbContext.Counsellors.Where(x => x.Id == teacherNo).Include(x => x.Students);
            if (!query.Any()) throw new ArgumentException("工号不存在");
            return query.Single();
        }
    }
}
